package com.cuit.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cuit.common.Constants;
import com.cuit.common.Result;
import com.cuit.entity.Voice;
import com.cuit.mapper.VoiceMapper;
import com.cuit.service.VoiceService;
import org.jaudiotagger.audio.AudioFile;
import org.jaudiotagger.audio.wav.WavFileReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.vosk.Model;
import org.vosk.Recognizer;

import javax.sound.sampled.AudioSystem;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.UUID;

@RestController
@RequestMapping("/api")
public class SpeechController {

    @Autowired
    private VoiceMapper voiceMapper;

    // 模型路径写死为相对路径
    private static final String MODEL_PATH = "src/main/resources/vosk-model-small-cn-0.22";

    /**
     * 处理音频文件上传并进行语音识别
     *
     * @param file 用户上传的音频文件
     * @return 识别结果封装在Result对象中
     */
    @PostMapping("/recognize")
    public Result recognize(@RequestParam("file") MultipartFile file) {

        try {
            // 保存上传的.wav文件到指定目录
            String fileName = UUID.randomUUID().toString() + ".wav";
            // 指定文件保存路径（请根据实际情况修改路径）
            String uploadDir = "D:/uploaded_files/";
            File destFile = new File(uploadDir + fileName);
            // 若目录不存在，创建目录
            if (!destFile.getParentFile().exists()) {
                destFile.getParentFile().mkdirs();
            }
            file.transferTo(destFile);

            // 使用保存好的文件进行语音识别
            try (Model model = new Model(MODEL_PATH);
                 InputStream ais = AudioSystem.getAudioInputStream(new BufferedInputStream(new FileInputStream(destFile)));
                 Recognizer recognizer = new Recognizer(model, getSampleRate(destFile))) {

                int bytes;
                byte[] b = new byte[4096];
                while ((bytes = ais.read(b)) >= 0) {
                    recognizer.acceptWaveForm(b, bytes);
                }
                String recognitionResult = recognizer.getFinalResult();
                JSONObject jsonObject = JSON.parseObject(recognitionResult);
                String text = jsonObject.getString("text");
                System.out.println("提取的文本: " + text);

                // 构建 Voice 对象，将识别后的文本和文件信息保存到数据库
                Voice voice = new Voice();
                voice.setText(text);
                voice.setFileName(fileName);
                voice.setFilePath(destFile.getAbsolutePath());
                voice.setCreateTime(LocalDateTime.now());

                // 保存到数据库中
                voiceMapper.insert(voice);

                return Result.success(text);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error(Constants.CODE_400, "Error: " + e.getMessage());
        }
    }

    /**
     * 获取音频文件的采样率
     *
     * 该方法通过读取音频文件的头信息来获取采样率
     * 使用了WavFileReader来读取文件，并从AudioFile对象中提取采样率信息
     *
     * @param file 音频文件对象，必须是有效的音频文件，否则会抛出异常
     * @return 返回音频文件的采样率，以浮点数形式表示
     * @throws Exception 如果文件读取过程中发生错误或文件格式不支持，则抛出异常
     */
    private Float getSampleRate(File file) throws Exception {
        // 创建WavFileReader实例来读取音频文件
        WavFileReader fileReader = new WavFileReader();
        // 读取音频文件并获取AudioFile对象
        AudioFile audioFile = fileReader.read(file);
        // 从AudioFile的头信息中获取采样率
        String sampleRate = audioFile.getAudioHeader().getSampleRate();
        // 将采样率字符串转换为浮点数并返回
        return Float.parseFloat(sampleRate);
    }

}